<template>
	<view class="vi_formCreator" :class="mainClass">
		<view class="vi_formCreator_group" v-for="(group, index) in inList" :key="index">
			<!-- 组标题 -->
			<view class="vi_formCreator_title" v-if="group[setting.groupTitleKey]">
				<vi-style-controller
					control="background"
					width="0.4em"
					height="1.4em"
					radius="0.2em"
					:type="setting.type"
					:color="color"
					inline
					active
					></vi-style-controller>
				<text class="vi_formCreator_titleText">{{group[setting.groupTitleKey]}}</text>
			</view>
			
			<view class="vi_item" v-for="(item, idx) in group[setting.groupItemKey]" :key="idx" v-if="!item.hide">
				<view class="vi_row"
					:class="{
						'vi_breakRow':item.breakRow||breakRow,
						'vi_err':item._checkFail,
						'vi_success':item.showSuccese && item._checkSuccese}">
						
					<!-- 标签 -->
					<view class="vi_label" v-if="item.label||(item.labelPlace!=undefined?item.labelPlace:setting.labelPlace)"
						:class="[item.labelClass||labelClass||'', 'vi_'+setting.labelAlign, {'vi_baseline':item.type=='textarea', 'vi_bold':labelBold}]"
						:style="{'width':item.breakRow||breakRow?'auto':setting.labelWidth+'em', 'margin-right':setting.space +'em'}"
						@click="showTip(item)">
						
						<!-- 内联模式，超出显示tip -->
						<view class="vi_tip" :class="{'vi_act':item._showTip}" v-if="!item.breakRow&&!breakRow">{{item.label}}</view>
						<!-- 标签正文，带必填星号 -->
						<view class="vi_box" :class="{'vi_hide':item._showTip}">
							<text class="iconfont" :class="iconSetting.required" v-if="item.label&&isRequired(item)&&!disabled"></text>
							<view class="vi_text" :style="{'width':item.breakRow||breakRow?'auto':setting.labelWidth+'em'}">{{item.label}}</view>
						</view>
					</view>
					<!-- 控件 -->
					<view class="vi_control" :class="[controlClass||'',{'vi_controlRight':controlRight}]">
						<view class="vi_flag" v-if="!item.label&&isRequired(item)&&!disabled">
							<text class="iconfont" :class="iconSetting.required"></text>
						</view>
						<!-- 前缀 -->
						<view class="vi_formCreator_addonBefore" :class="item.beforeAddon.class||''" v-if="item.beforeAddon&&['text','number','password','sendcode'].includes(item.type)">
							<text class="iconfont" :class="item.beforeAddon.icon" v-if="item.beforeAddon.icon"></text>
							<text v-else>{{item.beforeAddon.value}}</text>
						</view>
						
						<!-- 控件区 -->
						<view class="vi_controlBox" @click="onClick(item)"
							:class="['vi_'+item.type+'Box', {'disabled':disabled, 'readOnly':readOnly}]">
							
							<!-- 文本框 -->
							<input v-if="item.type=='text'&&(item.disabled||item.readOnly||disabled||readOnly)" type="text"
								:value="hideWords(item)"
								:disabled="true"
								placeholder-class="placeholder"
								:class="['input','vi_component',{'disabled':item.disabled||disabled, 'readOnly':item.readOnly||readOnly}]"/>
								
							<input v-if="item.type=='text'&&(!item.disabled&&!item.readOnly&&!disabled&&!readOnly)" type="text"
								:value="item.value"
								:maxlength="item.maxlength||setting.maxLength"
								:placeholder="(item.disabled||item.readOnly||disabled||readOnly)? '': (item.placeholder||textSetting.plcInput)"
								:disabled="item.disabled||item.readOnly||disabled||readOnly"
								@input="onInput($event,item)"
								@blur="onBlur(item)"
								placeholder-class="placeholder"
								:class="['input','vi_component',{'disabled':item.disabled||disabled, 'readOnly':item.readOnly||readOnly}]"/>
							
							<!-- 虚拟文本，使用显示值，由外部计算click进行值更改 -->
							<input v-if="item.type=='vtext'" type="text"
								:value="item.showValue"
								:disabled="true"
								:placeholder="(item.disabled||item.readOnly||disabled||readOnly)? '': (item.placeholder||'')"
								placeholder-class="placeholder"
								:class="['input','vi_component',{'disabled':item.disabled||disabled, 'readOnly':item.readOnly||readOnly}]"/>
							
							<!-- 文本框数字类型 -->
							<input v-if="item.type=='number'" type="number"
								:value="item.value"
								:maxlength="item.maxlength||setting.maxLength"
								:placeholder="(item.disabled||item.readOnly||disabled||readOnly)? '': (item.placeholder||textSetting.plcInput)"
								:disabled="item.disabled||item.readOnly||disabled||readOnly"
								@input="onInput($event,item)"
								@blur="onBlur(item)"
								placeholder-class="placeholder"
								:class="['input','vi_component',{'disabled':item.disabled||disabled, 'readOnly':item.readOnly||readOnly}]"/>
								
							<!-- 密码，自定义组件深层对象，微信使用v-model无效 -->
							<vi-password v-if="item.type=='password'"
								:value="item.value" :maxlength="item.maxlength||setting.maxLength"
								:placeholder="(item.disabled||item.readOnly||disabled||readOnly)? '': (item.placeholder||textSetting.plcInput)"
								:disabled="item.disabled||item.readOnly||disabled||readOnly"
								@input="onViInput($event,item)"
								@blur="onBlur(item)"
								placeholderClass="placeholder"
								class="vi_component"></vi-password>
			
							<!-- 发送验证码 -->
							<common-sendcode v-if="item.type=='sendcode'"
								:value="item.value"
								:placeholder="(item.disabled||item.readOnly||disabled||readOnly)? '': (item.placeholder||textSetting.plcInput)"
								:httpData="item.httpData"
								:keys="item.keys"
								:useLoginQuest="item.useLoginQuest"
								:disabled="item.disabled||item.readOnly||disabled||readOnly"
								@input="onViInput($event,item)"
								@blur="onBlur(item)"
								placeholderClass="placeholder"
								class="vi_component"></common-sendcode>
							
							<!-- 文本域 -->
							<textarea v-if="item.type=='textarea'"
								:value="item.value"
								:maxlength="item.maxlength||setting.areaMaxlength"
								:auto-height="item.autoHeight"
								:placeholder="(item.disabled||item.readOnly||disabled||readOnly)? '': (item.placeholder||textSetting.plcInput)"
								:disabled="item.disabled||item.readOnly||disabled||readOnly"
								@input="onInput($event,item)"
								@blur="onBlur(item)"
								placeholder-class="placeholder"
								:class="['textarea','vi_component',{'disabled':item.disabled||disabled, 'readOnly':item.readOnly||readOnly}]"
								:style="{'line-height':1.5,'height':(item.height||computeAreaRow(item.value))*1.5+1+'em'}"></textarea>
							
							<!-- 虚拟文本域，使用显示值，由外部计算click进行值更改 -->
							<textarea v-if="item.type=='vtextarea'"
								:value="item.showValue"
								:disabled="true"
								:auto-height="item.autoHeight"
								:placeholder="(item.disabled||item.readOnly||disabled||readOnly)? '': (item.placeholder||'')"
								placeholder-class="placeholder"
								:class="['textarea','vi_component',{'disabled':item.disabled||disabled, 'readOnly':item.readOnly||readOnly}]"
								:style="{'line-height':1.5,'height':(item.height||computeAreaRow(item.showValue))*1.5+1+'em'}"></textarea>
							
							<!-- 日期选择 -->
							<view :class="['vi_inComponent',{'disabled':item.disabled||disabled,'readOnly':item.readOnly||readOnly}]" v-if="['date','datetime','year'].includes(item.type)" @click="onOpenSelect(item,'datetime')">
								<text class="iconfont placeholder" :class="iconSetting.calendar"></text>
								<text v-if="item.showValue">{{item.showValue}}</text>
								<text v-else class="placeholder">{{(item.disabled||disabled||item.readOnly||readOnly)? '': (item.placeholder||textSetting.plcSelect)}}</text>
							</view>
							
							<!-- 选择器 -->
							<view :class="['vi_inComponent',{'disabled':item.disabled||disabled, 'readOnly':item.readOnly||readOnly}]" v-if="['select','tree','page'].includes(item.type)"  @click="onOpenSelect(item,'selector')">
								<text class="vi_showValue" v-if="item.showValue">{{item.showValue}}</text>
								<text class="vi_showValue placeholder" v-else>{{(item.disabled||disabled||item.readOnly||readOnly)? '': (item.placeholder||textSetting.plcSelect)}}</text>
								<text class="iconfont placeholder" :class="iconSetting.select"></text>
							</view>
							
							<!-- 复选框、单选框 -->
							<vi-checkbox-group v-if="item.type=='checkbox'||item.type=='radio'"
								:groupId="'formCheckbox'+cId"
								:isRadio="item.type=='radio'"
								:value="item.value"
								:disabled="item.disabled||disabled"
								:readOnly="item.readOnly||readOnly"
								@change="dataChange($event,item)"
								class="vi_component">
								<view class="vi-checkbox-group">
									<vi-checkbox :groupId="'formCheckbox'+cId" v-for="(opt,i) in item.options" :key="i"
										:type="setting.type"
										:size="setting.size"
										:color="color"
										:value="opt.value"
										:disabled="opt.disabled"
										:readOnly="opt.readOnly"
										:disabledMsg="opt.disabledMsg"
										:readOnlyMsg="opt.readOnlyMsg"
										class="vi_inComponent">
										<text :class="{'disabled':item.disabled||disabled, 'readOnly':item.readOnly||readOnly}">{{opt.name}}</text>
									</vi-checkbox>
								</view>
							</vi-checkbox-group>
							
							<!-- 滑动条，自定义组件深层对象，微信使用v-model无效 -->
							<vi-slider v-if="item.type=='slider'"
								:type="setting.type"
								:size="setting.size"
								:color="color"
								:radius="setting.radius"
								:value="item.value"
								:disabled="item.disabled||disabled"
								:readOnly="item.readOnly||readOnly"
								:range="item.range"
								:min="Number(item.min)||undefined"
								:max="Number(item.max)||undefined"
								:tips="item.tips"
								:unit="item.unit"
								:refreshWatcher="breakRow"
								class="vi_component"
								@change="dataChange($event,item)"></vi-slider>
							
							<!-- 开关 -->
							<view class="vi_component" v-if="item.type=='switch'">
								<view class="vi_text" v-if="item.template">
									<view v-html="item.template" @click="linkTo(item)"></view>
								</view>
								<view class="vi_text" v-else>
									<text class="placeholder" v-if="item.placeholder&&!(item.disabled||disabled||item.readOnly||readOnly)" @click="linkTo(item)">{{item.placeholder}}</text>
								</view>
								<vi-switch
									:type="setting.type"
									:size="setting.size"
									:color="color"
									:radius="setting.radius"
									:mode="item.mode"
									:checked="item.checked"
									:value="item.value"
									:onValue="item.onValue"
									:offValue="item.offValue"
									:disabled="item.disabled||disabled"
									:readOnly="item.readOnly||readOnly"
									@change="dataChange($event,item)">
										<text class="iconfont" :class="item.buttonIcon" v-if="item.buttonIcon"></text>
									</vi-switch>
							</view>
							
							<!-- 步进器 -->
							<view class="vi_component" v-if="item.type=='stepper'">
								<view class="vi_text" :style="{'order':item.align=='left'?2:1}">
									<text class="placeholder" v-if="item.placeholder&&!(item.disabled||disabled||item.readOnly||readOnly)">{{item.placeholder}}</text>
								</view>
								<view class="" :style="{'order':item.align=='left'?1:2}">
									<vi-stepper
										:type="setting.type"
										:size="setting.size"
										:color="color"
										:radius="setting.radius"
										:value="item.value"
										:min="item.min"
										:max="item.max"
										:step="item.step"
										:decimals="item.decimals"
										:fixDecimals="item.fixDecimals"
										:maxlength="item.maxlength"
										:boxWidth="item.boxWidth"
										:disabled="item.disabled||disabled"
										:readOnly="item.readOnly||readOnly"
										:useLongPress="item.useLongPress"
										:unit="item.unit"
										@change="dataChange($event,item)"></vi-stepper>
								</view>
							</view>
						</view>
						
						<!-- 后缀 -->
						<view class="vi_formCreator_addonAfter" :class="item.afterAddon.class||''" v-if="item.afterAddon&&['text','number','password','sendcode'].includes(item.type)">
							<text class="iconfont" :class="item.afterAddon.icon" v-if="item.afterAddon.icon"></text>
							<text v-else>{{item.afterAddon.value}}</text>
						</view>
					</view>
				</view>
				<!-- 一般提示 -->
				<view class="vi_formCreator_infoMsg" v-if="item.infoMsg">
					<view v-if="!item.breakRow&&!breakRow" :style="{'width':item.breakRow||breakRow?'auto':setting.labelWidth +setting.space +1 +'em'}"></view>
					<view class="vi_text">
						<text class="vi_ico iconfont" :class="iconSetting.info"></text>
						<text>{{item.infoMsg}}</text>
					</view>
				</view>
				<!-- 警告提示 -->
				<view class="vi_formCreator_warnMsg" v-if="item.warnMsg">
					<view v-if="!item.breakRow&&!breakRow" :style="{'width':item.breakRow||breakRow?'auto':setting.labelWidth +setting.space +1 +'em'}"></view>
					<view class="vi_text">
						<text class="vi_ico iconfont" :class="iconSetting.warning"></text>
						<text>{{item.warnMsg}}</text>
					</view>
				</view>
				<!-- 错误提示 -->
				<view class="vi_formCreator_errMsg" :class="{'vi_act':item._checkFail}" v-if="item._checkFail">
					<view v-if="!item.breakRow&&!breakRow" :style="{'width':item.breakRow||breakRow?'auto':setting.labelWidth +setting.space +1 +'em'}"></view>
					<view class="vi_text">
						<text class="vi_ico iconfont" :class="iconSetting.error"></text>
						<text>{{item._errMsg}}</text>
					</view>
				</view>
			</view>
		</view>
		
		<view class="vi_formCreator_submitBtn" v-if="inList.length&&!readOnly&&setting.useSubmit">
			<vi-button
				:type="setting.type"
				:color="color"
				:size="setting.size"
				:radius="setting.submitRadius"
				:width="submitWidth"
				:height="submitHeight"
				:disabled="disabled"
				@click="submitPre">
					{{textSetting.confirm}}
			</vi-button>
		</view>
		
		<!-- 日期选择组件 -->
		<vi-datetime ref="datetime" :mode="currItem.mode" v-if="['date','datetime','year'].includes(currItem.type)"
			:value="currItem.value"
			:resFormat="currItem.resFormat"
			:pickType="currItem.type"
			:start="currItem.start"
			:end="currItem.end"
			:min="currItem.min"
			:max="currItem.max"
			:disabled="currItem.disabled||disabled"
			:readOnly="currItem.readOnly||readOnly"
			:point="selectSetting.point"
			:useTitle="selectSetting.useTitle"
			:activeSubmit="selectSetting.activeSubmit"
			:boxRadius="selectSetting.boxRadius"
			:maxWidth="selectSetting.maxWidth"
			:weekSet="selectSetting.weekSet"
			:formatSet="selectSetting.formatSet"
			:text="textSetting"
			:icon="iconSetting"
			@submit="dateChange($event,currItem)"></vi-datetime>
		
		<!-- 选择器组件 -->
		<vi-select ref="selector" :mode="currItem.mode" v-if="['select','tree','page'].includes(currItem.type)"
			:isTree="['tree','page'].includes(currItem.type)?currItem.type:currItem.isTree||false"
			:treeSet="currItem.treeSet||emptyObj"
			:type="setting.type"
			:color="color"
			:dataList="currItem.options"
			:value="currItem.value"
			:min="currItem.min||0"
			:max="currItem.max||0"
			:keys="currItem.keys"
			resFormat="option"
			:disabled="currItem.disabled||disabled"
			:readOnly="currItem.readOnly||readOnly"
			:point="selectSetting.point"
			:useTitle="selectSetting.useTitle"
			:activeSubmit="selectSetting.activeSubmit"
			:boxRadius="selectSetting.boxRadius"
			:buttonHeight="selectSetting.buttonHeight"
			:iconReverse="selectSetting.iconReverse"
			:width="selectSetting.width"
			:maxWidth="selectSetting.maxWidth"
			:optionHeight="selectSetting.optionHeight"
			:maxHeight="selectSetting.maxHeight"
			:text="textSetting"
			:icon="iconSetting"
			@submit="selectChange($event,currItem)"></vi-select>
	</view>
</template>

<script>
	export default {
		name:"commonFormCreator",
		options:{//样式穿透，微信须设置
			styleIsolation: "shared"
		},
		props:{
			dataList:{
				type:[Array,null],
				default:()=>[
					// {
					// 	type:"text",	//控件类型：text、number、textarea、date、time、password、sendcode / checkbox、radio、select / slider、switch / region(包含了省市区数据，仅微信小程序支持) / 其他需重做的组件 clickNumber(按钮点击增减的数字框)、datetime、dateRange、timeRange、
					// 	name:"",		//控件id，用于打包输出form对象数据
					// 	label:"标签名字",//标签名
					//  labelClass:"标签样式名",//全局样式有效
					// 	labelPlace:true,//标签占位，标签名为空时默认去掉标签元素，用此标注空值占位
					// 	value:"",		//默认值，类型可能为string、number、array
					// 	disabled:false,	//控件禁用，带样式，优先于只读
					// 	readOnly:false,	//控件只读，带样式
					// 	breakRow:false,	//标签与控件换行，false即为标签与控件在同一行，为true时，label独占一行，labelWidth无效。
					// 	showValue:"",	//显示值(无)，用于显示值不等于实际值的控件，须对传入数据初始化。date、time、select
					// 	index:0,		//选项下标(无)，用于绑定下标的控件，须对传入数据初始化。select
						
					// 	//输入类型
					// 	placeholder:"",	//空值提示	text、number、password、date、time、textarea
					// 	password:false,	//密码隐藏	password
					// 	maxlength:140,	//最大输入长度	text、number、password
					// 	autoHeight:false,//自动增高	textarea
					// 	height:3,		//高度，字符行数		textarea
					// 	min:null,		//最小值		number
					// 	max:null,		//最大值		number
					// 	encode:{		//信息保护，非编辑模式才能使用	text
					// 		max:0,		//显示最大长度，多则略去
					// 		min:3,		//显示最小长度，少则补充
					// 		start:2,	//保留显示长度
					// 		replace:"*"//替换符
					// 	},
					// 	beforeAddon:{	//前缀	text、number
					// 		class:"",	//样式名，请使用全局样式
					// 		icon:"",	//显示的图标名（前置iconfont），优先于显示值
					// 		value:"",	//显示值
					// 	},
					// 	afterAddon:{	//后缀	text、number
					// 		class:"",	//样式名，请使用全局样式
					// 		icon:"",	//显示的图标名（前置iconfont），优先于显示值
					// 		value:"",	//显示值
					// 	},
						
					// 	//选择类型
					// 	mode:"",		//选择模式，可选radio、checkbox模式	select
					// 	isTree:false,	//是否树，可选tree普通树、page翻页树	select
					// 	min:1,			//最小选择数量	select
					// 	max:null,		//最大选择数量	select
					// 	treeSet:{		//选择模式为tree、page时使用，内部树设置	select
					// 		// ……		//参照vi-select组件内定义
					// 	},
					// 	keys:{			//数据关键字设置
					// 		// ……		//参照vi-select组件内定义
					// 	},
					// 	options:[				//选项列表	checkbox、radio、select
					// 		{
					// 			name:"",		//显示值
					// 			value:"",		//实际值
					// 			disabled:false,	//选项禁用，checkbox、radio
					// 			readOnly:false,	//选项锁定，checkbox、radio
					// 		}
					// 	],
						
					// 	//日期时间
					// 	mode:"radio"	//选择类型，可选radio、checkbox，range	date、datetime
					// 	format:"",		//显示值的转换格式	date、datetime
					// 	resFormat:"",	//结果数据类型	默认时间戳，可选ISO、UTC、Date以及自定义格式化字符串	date、datetime
					// 	start:"",		//开始时间	date、datetime
					// 	end:"",			//结束时间	date、datetime
					// 	min:0,			//最小选择数	date、datetime
					// 	max:10,			//最大选择数	date、datetime
						
					// 	//switch使用
					// 	placeholder:"",
					// 	mode:"",		//绑定值模式	不设置为正常模式(返回true或false)，value绑定值模式(须配置onValue，可配置offValue)
					// 	onValue:"",		//开关开启值
					// 	offValue:"",	//开关关闭值
					// 	buttonText:"",	//开关按钮显示文本
					// 	buttonIcon:"",	//开关按钮显示图标，优先于文本
					// 	buttonClass:"",	//开关按钮样式
					// 	checked:false,	//是否默认选中，非绑定值模式时有效
					// 	template:"",	//显示内容模板，注意模板内容不会二次解析，无法使用组件，无法触发事件
					// 	url:"",			//内容点击跳转链接
					// 	urlType:undefined,//跳转类型
						
					// 	//slider使用
					// 	range:false,	//开启选区
					// 	min:0,		//最小值	，或最小数量	slider、stepper
					// 	max:100,		//最大值	，或最大数量	slider、stepper
					// 	tips:true,		//当前数值显示方式
					// 	unit:"",		//数值单位
						
					// 	//步进器使用
					// 	step:1,			//步进
					// 	decimals:0,		//数据允许小数位
					//  fixDecimals:0,	//固定显示小数位
					// 	maxlength:4,	//最大输入长度
					// 	boxWidth:0,		//输入框宽度
						
					// 	//表单验证用
					// 	checkRule:"",
					// 	errMsg:"",
					// 	showSuccese:false,//验证成功的显示成功样式，需要立即验证
					
					// 	//提示用
					// 	infoMsg:"",
					//  warnMsg:"",
						
					// 	//外部计算，填入处理信息，通过params参数返回
					// 	//提交数据格式：
					// 	/*	{
					// 			event: "init",
					// 			params: item.compute.init,
					// 			item: item,
					// 			data: this.inList,
					// 		}
					// 	*/
					// 	compute:{
					// 		init:[],		//初始化内部克隆数据、计算字段初始值后
					// 		click:[],		//控件点击时。注意设置控件只读
					// 		input:[],		//输入型控件，输入时
					// 		blur:[],		//输入型控件，离开时
					// 		change:[],		//控件值改变时
					// 		// submit		不可用，异步处理可能在提交后才执行
					// 	},
					// }
				]
			},
			//标签宽
			labelWidth:{
				type:[Number,null],
				default:0
			},
			//标签
			labelAlign:{
				type:[String,null],
				default:""
			},
			controlRight:{
				type:[Boolean,null],
				default:false
			},
			//标签样式名，请使用全局样式
			labelClass:{
				type:[String,null],
				default:""
			},
			//标签加粗
			labelBold:{
				type:[Boolean,null],
				default:false
			},
			//控件样式名，请使用全局样式
			controlClass:{
				type:[String,null],
				default:""
			},
			formClass:{
				type:[String,null],
				default:""
			},
			//表单样式，normal下划线类型、table单元格类型
			formStyle:{
				type:[String,null],
				default:""
			},
			//预设尺寸,sm、md、lg。与特殊控件尺寸同步
			size:{
				type:[String,null],
				default:null
			},
			//标签和控件间距，单位字符
			space:{
				type:[Number,null],
				default:null
			},
			labelPlace:{
				type:[Boolean,null],
				default:null
			},
			breakRow:{
				type:[Boolean,null],
				default:false
			},
			maxLength:{
				type:[Number,null],
				default:0
			},
			areaMaxlength:{
				type:[Number,null],
				default:0
			},
			//文本区默认高度，单位行数
			areaHeight:{
				type:[Number,null],
				default:0
			},
			//文本扩展高度，字数达到多少设为多高。格式[行数,达到字数]或{rows:行数,words:达到字数}
			areaExtendHeight:{
				type:[Array,null],
				default:null
			},
			submitWidth:{
				type:[String,Number],
				default:""
			},
			submitHeight:{
				type:[String,Number,null],
				default:""
			},
			submitRadius:{
				type:[String,Number,null],
				default:null
			},
			submitDelay:{
				type:[String,Number,null],
				default:""
			},
			type:{
				type:[String,null],
				default:null
			},
			color:{
				type:[String,null],
				default:""
			},
			//按钮圆角，选项只有圆circle，和方square
			radius:{
				type:[String,Number,null],
				default:null
			},
			disabled:{
				type:[Boolean,null],
				default:false
			},
			readOnly:{
				type:[Boolean,null],
				default:false
			},
			useSubmit:{
				type:[Boolean,null],
				default:null
			},
			activeSubmit:{
				type:[Boolean,null],
				default:false
			},
			//使用组，数据多套一层结构
			useGroup:{
				type:[Boolean,null],
				default:false
			},
			//组标题所在键名，针对于组
			groupTitleKey:{
				type:[String,null],
				default:""
			},
			//字段列表所在键名，针对于组
			groupItemKey:{
				type:[String,null],
				default:""
			},
			//选择弹窗设置集
			selectSet:{
				type:[Object,null],
				default:()=>({})
			},
			//图标设置
			icon:{
				type:[Object,null],
				default:()=>({})
			},
			text:{
				type:[Object,null],
				default:()=>({})
			}
		},
		data() {
			return {
				emptyObj:{},//小程序不能在模板属性中写空对象
				cId:"",
				inList:[],
				currItem:{},
				dicSelectSet:{
					point:"bottom",
					boxRadius:"0.5em",
					buttonHeight:3,
					iconReverse:false,
					width:"75vw",
					maxWidth:"40em",
					optionHeight:3,
					maxHeight:"65vh",
					activeSubmit:true,
					useTitle:false,
					weekSet:{},
					formatSet:{}
				},
				dicIcon:{
					required:"icon-required",
					calendar:"icon-calendar",
					select:"icon-arr-down",
					info:"icon-information",
					warning:"icon-err",
					error:"icon-err",
				},
				dicText:{
					confirm: "提交",
					tipFormError: "您填写的信息有误，请修改后提交",
					tipFieldEqualError: "输入内容必须与字段${value}的内容一致",
					plcSelect: "请选择",
					plcInput: "请输入",
				}
			}
		},
		computed:{
			//将默认值内含到css、计算属性等地方，只内含真值
			//规避特殊使用的情况下，由prop传入undefined、null等无效数据导致的，默认值失效问题。例如组件嵌套且需要组件间参数传递
			//HBuilder X3.3.13; 微信开发者工具stable 1.05.2111300
			//微信小程序会对传入的undefined、null值根据参数类型输出不同空值(false、""、null、0)，参数类型为null或未指定参数类型则输出null
			//H5会对传入的undefined取默认值，未设默认值则输出undefined。对传入的null值固定输出null
			//做参数传递时需警惕两者行为不同而造成的陷阱，主要问题出现在微信小程序的空值转化，输出非用户传入的空值、假值，使默认真值丢失
			//兼容空值取默认值的可行方案目前为，参数类型加入null如[Boolean,null]，判断传入参数是否为定义的类型，是则使用，否则赋予默认值
			setting(){
				return {
					type: this.$api.isDefined(this.type)? this.type :"primary",
					labelWidth: this.labelWidth ||6,
					size: this.$api.isDefined(this.size)? this.size :"md",
					radius: this.$api.isDefined(this.radius)? this.radius :"circle",
					space: this.$api.isValue(this.space)? this.space :1,
					labelPlace: this.$api.isBoolean(this.labelPlace)? this.labelPlace :true,
					useSubmit: this.$api.isBoolean(this.useSubmit)? this.useSubmit :true,
					groupTitleKey: this.groupTitleKey ||"name",
					groupItemKey: this.groupItemKey ||"children",
					labelAlign: this.labelAlign ||"left",
					formStyle: this.formStyle ||"normal",
					maxLength: this.maxLength ||140,
					areaMaxlength: this.areaMaxlength ||500,
					submitRadius: this.$api.isDefined(this.submitRadius)? this.submitRadius :"circle",
				}
			},
			textSetting(){
				if(this.$api.isObject(this.text)){
					return Object.assign({},this.dicText,this.text)
				}
				return this.dicText
			},
			mainClass(){
				let res = `${this.formClass||""} `;
				res += `vi_${this.setting.formStyle} `;
				res += `vi_${this.setting.size} fontSize-${this.setting.size} `;
				return res
			},
			selectSetting(){
				if(this.$api.isObject(this.selectSet)){
					return Object.assign({}, this.dicSelectSet, this.selectSet)
				}
				return this.dicSelectSet
			},
			iconSetting(){
				if(this.$api.isObject(this.icon)){
					return Object.assign({}, this.dicIcon, this.icon)
				}
				return this.dicIcon
			}
		},
		methods: {
			showTip(item){
				if(item.breakRow||this.breakRow){
					return
				}
				if(this.$api.lengthOf(item.label, {CN2: true}) > this.setting.labelWidth*2){
					if(item._tipTimer){
						clearTimeout(item._tipTimer)
					}
					item._showTip = true;
					this.$forceUpdate();
					item._tipTimer = setTimeout(()=>{
						item._showTip = false;
						this.$forceUpdate();
					},2000)
				}
			},
			isRequired(item){
				if(this.$api.isArray(item.checkRule)){
					for(let opt of item.checkRule){
						if(opt == "required" || (this.$api.isObject(opt) && opt.rule == "required")){
							return true
						}
					}
					return false
				}else{
					return String(item.checkRule).includes("required")
				}
			},
			hideWords(item){
				if(item.encode){
					return this.$api.hideWords(String(item.value), item.encode)
				}else{
					return item.value
				}
			},
			linkTo(item){
				if(!item.url){
					return
				}
				this.$api.linkTo(item.url, item.urlType)
			},
			computeAreaRow(string){
				let len = this.$api.lengthOf(string,{CN2:true}) /2,
					extendHeight = this.areaExtendHeight ||[[5,100],[8,160],[12,240]],
					rows = this.areaHeight ||3;
				if(extendHeight.length){
					for(let item of extendHeight){
						let typeAsk = this.$api.typeAsk(item);
						if(typeAsk=="Array"){
							if(len>=item[1] && rows<item[0]){
								rows = item[0]
							}
						}else if(typeAsk=="Object"){
							if(len>=item.words && rows<item.rows){
								rows = item.rows
							}
						}
					}
				}
				return rows
			},
			/*
				数据变更事件 start
			*/
			onOpenSelect(item, name){
				if(item.disabled||item.readOnly||this.disabled||this.readOnly){
					return
				}
				this.currItem = item;
				this.$nextTick(()=>{
					this.$refs[name].open();
				})
			},
			onClick(item){
				//判断触发外部计算
				if(item.compute.click.length){
					this.$emit("compute", {
						event: "click",
						params: item.compute.click,
						item,
						data: this.inList,
					})
				}
			},
			onInput(e,item){//通用输入
				if(item.type=="number"){
					item["value"] = e.target.value ===""? "" :Number(e.target.value)
				}else{
					item["value"] = e.target.value;
				}
				item["_hasChange"] =true;
				//判断触发外部计算
				if(item.compute.input.length){
					this.$emit("compute", {
						event: "input",
						params: item.compute.input,
						item,
						data: this.inList,
					})
				}
			},
			onViInput(e,item){
				item["value"] = e;
				item["_hasChange"] =true;
				//判断触发外部计算
				if(item.compute.input.length){
					this.$emit("compute", {
						event: "input",
						params: item.compute.input,
						item,
						data: this.inList,
					})
				}
			},
			onBlur(item){//输入离开，当做改变
				if(item.type=="number"){//数字要判断大小限制
					let min = Number(item.min),
						max = Number(item.max);
					isNaN(min)?min=-Infinity:"";
					isNaN(max)?max=Infinity:"";
					if(max>=min){
						let val = item.value;
						if(val>max){
							item.value = max
						}else if(val<min){
							item.value = min
						}
					}
				}
				//已发生输入，为改变事件
				if(item._hasChange){
					delete item._hasChange;
					this.dataCheck(item);
					if(item.compute.change.length){
						this.$emit("compute", {
							event: "change",
							params: item.compute.change,
							item,
							data: this.inList,
						})
					}
				}
				//判断触发外部计算
				if(item.compute.blur.length){
					this.$emit("compute", {
						event: "blur",
						params: item.compute.blur,
						item,
						data: this.inList,
					})
				}
			},
			dataChange(e,item){//通用改变
				item["value"] = e;
				this.dataCheck(item);
				//判断触发外部计算
				if(item.compute.change.length){
					this.$emit("compute", {
						event: "change",
						params: item.compute.change,
						item,
						data: this.inList,
					})
				}
			},
			dateChange(e,item){
				item["value"] =e;
				this.setShowValue(item);
				this.$forceUpdate();
				this.dataCheck(item);
				//判断触发外部计算
				if(item.compute.change.length){
					this.$emit("compute", {
						event: "change",
						params: item.compute.change,
						item,
						data: this.inList,
					})
				}
			},
			selectChange(option, item){
				//单选
				if(!item.mode||["radio","show"].includes(item.mode)){
					item["showValue"] = option? option.name :"";
					item["value"] = option? option.value :null;
				}else{//多选
					item["showValue"] = option.map((opt)=>{ return opt.name}).join(", ");
					item["value"] = option.map((opt)=>{ return opt.value});
				}
				this.$forceUpdate();
				this.dataCheck(item);
				//判断触发外部计算
				if(item.compute.change.length){
					this.$emit("compute", {
						event: "change",
						params: item.compute.change,
						item,
						data: this.inList,
					})
				}
			},
			/*
				数据变更事件 end
			*/
			//立即校验数据
			dataCheck(item){
				//处理小数位
				if(["number","stepper"].includes(item.type)&&this.$api.isNumber(item.fixed, true)){
					item["value"] = this.$api.numberFix(item.value, Number(item.fixed))
				}
				if(this.activeSubmit){
					//动态提交，立即进入全表单校验
					this.submit()
				}else if(item.showSuccese){
					let testValue;
					if(this.$api.isArray(item.value)){//结果是数组，只能校验非空
						testValue = String(item.value.length)
					}else{
						testValue = String(item.value)
					}
					let checkObj = this.$api.regCheck(testValue, item.checkRule, {notRequired:true, msg:true});
					if(checkObj.res){//校验成功
						item["_checkSuccese"] = true;
						item["_checkFail"] = false;
					}else{
						item["_checkSuccese"] = false;
						item["_checkFail"] = true;
						item["_errMsg"] = item.errMsg || checkObj.msg;
					}
					this.$forceUpdate();
				}
			},
			//提交前置
			submitPre(){
				if(this.submitDelay){
					setTimeout(()=>{
						this.submit()
					},Number(this.submitDelay)||0)
				}else{
					this.submit()
				}
			},
			//提交事件，校验通过后向外提交数据
			submit(){
				if(this.disabled||this.readOnly){
					return
				}
				let checkPass = true;
				this.mapGroupItem((item)=>{
					if(!item.checkRule || item.hide){//隐藏字段不校验
						return
					}
					let checkObj;
					//与某字段值相等比较
					if(this.$api.isObject(item.checkRule) && item.checkRule.rule == "sameWith"){
						let target = this.$api.arrFind(this.inList, {key:"name", value:item.checkRule.value, format:"item"});
						let msg = this.textSetting.tipFieldEqualError.replace("${value}", item.checkRule.value);
						checkObj = {
							res: target.value === item.value,
							msg: msg
						}
					}else{
						checkObj = this.$api.regCheck(item.value, item.checkRule, {notRequired:true, msg:true});
					}
					//_checkSuccese、_checkFail使用地方不一样
					item["_checkSuccese"] = checkObj.res;
					item["_checkFail"] = !checkObj.res;
					item["_errMsg"] = item.errMsg || checkObj.msg;
					if(!checkObj.res){
						checkPass = false
					}
				})
				this.$forceUpdate();
				//校验完成，组装返回数据
				if(checkPass){
					let res = this.getData();
					this.$emit("submit", res, this.inList);
					//外部调用返回
					return {res, data:this.inList}
				}else{
					this.$api.msg(this.textSetting.tipFormError, "error")
				}
				//外部调用返回
				return null
			},
			//获取表单当前结果数据，可外部使用
			getData(){
				let res = {};
				this.mapGroupItem((item)=>{
					if(item.name){
						res[item.name] = item.value;
						//特殊类型数据处理
						if(item.type=="select"&&item.mode=="checkbox"&&item.resFormat=="string"&&this.$api.isArray(item.value)){
							res[item.name] = item.value.join();
						}
					}
				})
				return res
			},
			//初始化，部分控件须初始赋值
			refresh(){
				if(!this.dataList||!this.dataList.length){
					this.inList =[];
					return
				}
				this.inList = this.$api.clone(this.dataList);
				//非组使用时，多套一层组数据
				if(!this.useGroup){
					let group = [{}];
					group[0][this.setting.groupTitleKey] = "";
					group[0][this.setting.groupItemKey] = this.inList;
					this.inList = group;
				}
				this.mapGroupItem((item, gId, id)=>{
					item["_gid"] =gId;
					item["_id"] =gId+"-"+id;
					item["_index"] =id;
					if(!item.compute){
						item["compute"] ={
							init:[],
							click:[],
							input:[],
							blur:[],
							change:[],
						};
					}else{
						let compute = item.compute;
						compute.init?"":compute.init=[];
						compute.click?"":compute.click=[];
						compute.input?"":compute.input=[];
						compute.blur?"":compute.blur=[];
						compute.change?"":compute.change=[];
					}
					//如果数据集附带值，计算显示值
					if(this.$api.isValue(item.value)){
						this.setShowValue(item);
					}
				});
				//检查外部计算，提交事件
				this.mapGroupItem((item)=>{
					if(item.compute.init.length){
						this.$emit("compute", {
							event: "init",
							params: item.compute.init,
							item,
							data: this.inList,
						})
					}
				});
				//提交创建完成事件，可在下一步赋值
				this.$emit("ready")
			},
			//设置表单字段值，外部用
			setValue(valueObj){
				if(!this.$api.isObject(valueObj)){ return }
				this.mapGroupItem((item)=>{
					if(this.$api.isValue(valueObj[item.name])){
						item["value"] = valueObj[item.name];
						//设置显示值，如为特殊显示值须用setFields手动指定
						this.setShowValue(item);
					}
				})
			},
			//设置表单字段数据，外部用。两种格式
			//对象格式：字段键名:{字段属性名:字段属性值}
			//数组格式：{name:"字段键名",字段属性名:"字段属性值"}
			setFields(data){
				let dataList =[];
				if(this.$api.isObject(data)){
					let keys = Object.keys(data);
					for(let key of keys){
						let item = data[key];
						item["name"] = key;
						dataList.push(item)
					}
				}else if(this.$api.isArray(data)){
					dataList = data
				}
				//覆盖数据
				for(let dataObj of dataList){
					this.mapGroupItem((item)=>{
						if(item.name==dataObj.name){
							Object.assign(item,dataObj);
							return "return"
						}
					})
				}
				this.update();
			},
			//设置字段显示值，通用类型
			setShowValue(item){
				switch(item.type){
					case "select":
						if(this.$api.isValue(item.value)&&item.options){//注意options数据存在的情况下才处理，否则在其他途径手动处理
							if(item.isTree){//树
								if(!item.keys){ break }
								let fItem;
								if(item.mode=="checkbox"){
									let tempVal = item[item.keys.value];
									let valueArr = typeof(tempVal)=="string"? valueArr = tempVal.split(",") :tempVal;
									fItem = [];
									this.$api.treeMap(item.options, (node)=>{
										if(valueArr.includes(node[item.keys.value])){
											fItem.push(node)
										}
									}, {key:item.keys.children});
									if(fItem.length){
										item["showValue"] = fItem.map((it)=>{return it[item.keys.name]}).join(", ")
									}
								}else{
									this.$api.treeMap(item.options, (node)=>{
										if(node[item.keys.value]==item[item.keys.value]){
											fItem = node;
											return "return"
										}
									}, {key:item.keys.children});
									if(fItem){
										item["showValue"] = fItem[item.keys.name]
									}
								}
							}else if(item.options.length){//普通选项列表
								if(item.mode=="checkbox"){
									let tempVal = item.value;
									let valueArr = typeof(tempVal)=="string"? valueArr = tempVal.split(",") :tempVal;
									let rsName =[];
									for(let val of (valueArr||[])){
										let fItem = this.$api.arrFind(item.options,{key:"value",value:val,format:"item"});
										if(fItem){
											rsName.push(fItem.name)
										}
									}
									item["showValue"] = rsName.join(", ");
								}else{
									let fItem = this.$api.arrFind(item.options,{key:"value",value:item.value,format:"item"});
									item["showValue"] = fItem? fItem.name: "";
								}
							}
						}
						break;
					case "date"://value默认为时间戳
						if(!item.mode||item.mode=="radio"){
							item["showValue"] = this.$api.dateFormat(item.value)
						}else if(item.mode=="checkbox"){
							if(item.value.length>2){
								item["showValue"] = `${item.value[0]}, ${item.value[1]} ...`
							}else{
								item["showValue"] = item.value.join(", ")
							}
						}else if(item.mode=="range"){
							item["showValue"] = item.value.join(" 至 ")
						}
						break;
					case "datetime"://固定为单选日期+时间
						item["showValue"] = this.$api.dateFormat(item.value, {format:item.format||"YYYY-MM-DD hh:mm"})
						break;
					case "year":
						item["showValue"] = item.value;
						break;
					case "switch":
						if(!item.mode||item.mode=="check"){
							item.checked = !!item.value
						}else if(item.mode=="value"){
							item.checked = item.value === item.onValue
						}
						break;
				}
			},
			//遍历表单字段
			mapGroupItem(func){
				for(let i=0, iLen=this.inList.length; i<iLen; i++){
					let group = this.inList[i];
					for(let j=0, jLen=group[this.setting.groupItemKey].length; j<jLen; j++ ){
						func(group[this.setting.groupItemKey][j], i, j)
					}
				}
			},
			//更新渲染，外部使用
			update(){
				this.$forceUpdate()
			}
		},
		watch:{
			"dataList":{
				immediate:true,
				handler(newVal){
					this.refresh()
				}
			},
		},
		created() {
			this.cId = `el${Math.ceil(Math.random() * 10e10).toString(36)}`
		}
	}
</script>

<style lang="scss" scoped>
$height-sm: 2em;
$height-md: 2.5em;
$height-lg: 3em;
$labelTip-border-color: #fcdeb5;
$labelTip-background-color: #fff6ea;
$border-color: #ddd;
$placeholder-color:#999;
$transition:.3s;
.vi_formCreator{
	padding: .5em 0.75em;
	line-height: 1.5;
	.input,.textarea{
		font-size: inherit;
	}
	.input{
		line-height: 1.5;
		height: 1.5em;
	}
	&.vi_sm .vi_row{
		min-height: $height-sm;
		&.vi_breakRow .vi_control{
			min-height: $height-sm;
		}
	}
	&.vi_md .vi_row{
		min-height: $height-md;
		&.vi_breakRow .vi_control{
			min-height: $height-md;
		}
	}
	&.vi_lg .vi_row{
		min-height: $height-lg;
		&.vi_breakRow .vi_control{
			min-height: $height-lg;
		}
	}
	.vi_formCreator_group{
		margin-bottom: 2em;
		&:last-child{
			margin-bottom: 0;
		}
	}
	.vi_formCreator_title{
		display: flex;
		align-items: center;
		padding-top: 0.25em;
		.vi_formCreator_titleText{
			margin-left: 0.5em;
			flex-grow: 1;
		}
	}
	.vi_item{
		position: relative;
		padding: .5em 0;
		margin-top: 0.5em;
		&:last-child{
			margin-bottom:0
		}
		.vi_row{//标签控件同一行
			display: flex;
			align-items: center;
			padding-left: 1em;
			position: relative;
			.icon-required{
				position: absolute;
				left: -1em;
				top: 50%;
				transform: translateY(-50%);
				color: red;
			}
			.vi_label{
				flex-shrink: 0;
				display: flex;
				justify-content: flex-start;
				// position: relative;
				&.vi_right{
					// justify-content: flex-end;
					text-align: right;
				}
				&.vi_center{
					// justify-content: center;
					text-align: center;
				}
				&.vi_baseline{
					align-self: baseline;
				}
				&.vi_bold{
					font-weight: bold;
				}
				.vi_box{
					position: relative;
					transition: opacity $transition;
					opacity: 1;
					.vi_text{
						position: relative;
						white-space: nowrap;
						overflow: hidden;
						text-overflow: ellipsis;
					}
					&.vi_hide{
						opacity: 0;
					}
				}
				.vi_tip{
					max-width: calc(100vw - 4em);
					// overflow: hidden;
					// text-overflow: ellipsis;
					// white-space: nowrap;
					
					padding: .35em .5em;
					position: absolute;
					top: calc(-0.175em);
					left: calc(0.5em - 1px);
					z-index: -1;
					background-color: $labelTip-background-color;
					border: 1px solid $labelTip-border-color;
					opacity: 0;
					transition: opacity $transition;
					&.vi_act{
						z-index: 10;
						opacity: 1;
					}
				}
			}
			.vi_control{
				flex-grow: 1;
				display: flex;
				align-items: center;
				position: relative;
				&.vi_controlRight{
					text-align: right;
					.vi_dateBox .vi_inComponent,
					.vi_datetimeBox .vi_inComponent,
					.vi_yearBox .vi_inComponent,
					.vi_checkboxBox .vi-checkbox-group,
					.vi_radioBox .vi-checkbox-group{
						justify-content: flex-end;
					}
				}
				/deep/ .placeholder{
					color: $placeholder-color;
				}
				.vi_flag{
					position: relative;
				}
				.vi_formCreator_addonBefore,
				.vi_formCreator_addonAfter{
					line-height: 1.5;
				}
				.vi_controlBox{
					flex-grow: 1;
					.disabled{
						color: $vi-txtColor-disable;
					}
					.vi_component{
						width: 100%;
					}
					&.vi_textBox,
					&.vi_vtextBox,
					&.vi_numberBox{
						height: 1.5em;
					}
					&.vi_textareaBox,
					&.vi_vtextareaBox{
						overflow: hidden;
					}
					&.vi_textareaBox .vi_component,
					&.vi_vtextareaBox .vi_component{
						padding: .5em;
						border-radius: .25em;
						box-sizing: border-box;
					}
					&.vi_selectBox .vi_inComponent{
						width: 100%;
						display: flex;
						align-items: center;
						.vi_showValue{
							flex-grow: 1;
							width: 0;
							margin-right: 0.25em;
							overflow: hidden;white-space: nowrap;text-overflow: ellipsis;
						}
					}
					&.vi_dateBox .vi_inComponent,
					&.vi_datetimeBox .vi_inComponent,
					&.vi_yearBox .vi_inComponent{
						display: flex;
						align-items: center;
						.iconfont{
							margin-right: .5em;
							font-size: 130%;
						}
					}
					&.vi_checkboxBox,
					&.vi_radioBox{
						.vi-checkbox-group{
							display: flex;
							align-items: center;
							flex-wrap: wrap;
							width: 100%;
						}
						.vi_inComponent{
							margin: .25em 1.5em .25em 0;
							&:last-child{
								margin-right: 0;
							}
						}
					}
					&.vi_switchBox .vi_component{
						display: flex;
						align-items: center;
						.vi_text{
							flex-grow: 1;
							line-height: 1.5;
						}
					}
					&.vi_stepperBox .vi_component{
						display: flex;
						.vi_text{
							flex-grow: 1;
						}
					}
				}
			}
			&.vi_breakRow{
				flex-direction: column;
				align-items: stretch;
				.vi_label{
					margin-right: 0 !important;
					margin-bottom: .5em;
					.vi_box{
						line-height: 1.5;
						.icon-required{
							transform: translateY(-50%);
						}
					}
				}
			}
		}
	}
	.vi_formCreator_submitBtn{
		margin-top: 2em;
	}
	
	//表单皮肤
	&.vi_normal,
	&.vi_noborder{
		.vi_item{
			padding-left: .5em;
			padding-right: .5em;
			border-bottom: 1px solid $border-color;
			&:last-child{
				border-bottom:0
			}
			.vi_textareaBox .vi_component,
			.vi_vtextareaBox .vi_component{
				background-color: #f8f8f8;
			}
		}
		.vi_formCreator_addonBefore{
			margin-right: .5em;
		}
		.vi_formCreator_addonAfter{
			margin-left: .5em;
		}
	}
	&.vi_noborder .item{
		border-bottom:0
	}
	&.vi_table{
		.vi_err{
			.vi_flag + view:not(.vi_control){
				border-left-color: $vi-color-error;
			}
			.vi_control{
				>view{
					border-top-color: $vi-color-error !important;
					border-bottom-color: $vi-color-error !important;
					&:first-child{
						border-left-color: $vi-color-error;
					}
					&:last-child{
						border-right-color: $vi-color-error;
					}
				}
			}
		}
		.vi_success{
			.vi_control{
				>view{
					border-color: $vi-color-success;
				}
				.vi_controlBox{
					&.vi_checkboxBox,
					&.vi_radioBox{
						padding-left: 0.5em;
					}
				}
			}
		}
		.vi_row.V{
			.vi_label{
				margin-bottom: .75em;
			}
		}
		.vi_control{
			align-self: stretch;
			align-items: stretch;
			>view{
				display: flex;
				align-items: center;
				&:first-child{
					border-top-left-radius: .25em;
					border-bottom-left-radius: .25em;
				}
				&:last-child{
					border-top-right-radius: .25em;
					border-bottom-right-radius: .25em;
				}
			}
			.vi_controlBox{
				padding: .5em .5em;
				&.vi_textareaBox,
				&.vi_vtextareaBox{
					padding:0
				}
				&.vi_checkboxBox,
				&.vi_radioBox{
					padding:0;
					.vi_inComponent{
						margin: .65em .75em .65em .75em;
						&:last-child{
							margin-right: 0;
						}
					}
				}
				&.vi_textBox,
				&.vi_vtextBox,
				&.vi_numberBox,
				&.vi_passwordBox,
				&.vi_sendcodeBox,
				&.vi_textareaBox,
				&.vi_vtextareaBox,
				&.vi_dateBox,
				&.vi_datetimeBox,
				&.vi_yearBox,
				&.vi_timeBox,
				&.vi_selectBox{
					border: 1px solid $border-color;
				}
			}
			.vi_formCreator_addonBefore{
				padding: .5em .45em;
				border: 1px solid $border-color;
				border-right: 0;
				border-top-left-radius: .25em;
				border-bottom-left-radius: .25em;
				background: linear-gradient(180deg, rgba(0,0,0,.02), rgba(0,0,0,.1));
			}
			.vi_formCreator_addonAfter{
				padding: .5em .45em;
				border: 1px solid $border-color;
				border-left: 0;
				border-top-right-radius: .25em;
				border-bottom-right-radius: .25em;
				background: linear-gradient(180deg, rgba(0,0,0,.02), rgba(0,0,0,.1));
			}
		}
	}
	.vi_formCreator_infoMsg,
	.vi_formCreator_warnMsg,
	.vi_formCreator_errMsg{
		display: flex;
		line-height: 1.5;
		.vi_text{
			flex-grow: 1;
		}
		.vi_ico{
			display: inline;
			margin-right: 0.25em;
		}
	}
	.vi_formCreator_infoMsg{
		color: $vi-color-info;
	}
	.vi_formCreator_warnMsg{
		color: $vi-color-warning;
	}
	//错误提示,最多4行
	.vi_formCreator_errMsg{
		max-height: 0;
		overflow: hidden;
		color: $vi-color-error;
		transition: $transition;
		&.vi_act{
			max-height:6em
		}
	}
}
</style>
